/******************************************************************************
*  author: enquanyan
*  version: 1.0
*  description:
*  			forward_conn header file;
*  date: 2014-08-04
*  other: 无
******************************************************************************/

#ifndef FORWARD_CONN_H
#define FORWARD_CONN_H

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/sendfile.h>
#include <stdarg.h>
#include <errno.h>
#include <dirent.h>
#include "locker.h"
#include "def.h"
#include "threadpool.h"
#include "abstract_conn.h"

//set file descriptor to non-block
extern int setnonblocking(int fd);

//add fd to epoll
extern int addfd(int epollfd, abstract_conn * abstract_conn_ptr, int fd, bool one_shot);

//add fd to epoll
extern int addfd_EPOLLOUT(int epollfd, abstract_conn * abstract_conn_ptr, int fd, bool one_shot = true);

//remove fd from epoll
extern int removefd(int epollfd, int fd, bool is_in_epoll);

//modify fd
extern int modfd(int epollfd, abstract_conn * abstract_conn_ptr, int fd, int ev, bool is_in_epoll);

class forward_conn : public abstract_conn
{
    public:
        typedef bool (forward_conn::*read_handle_t)();

        typedef bool (forward_conn::*write_handle_t)();

    public:
    
        forward_conn();
        virtual ~forward_conn();

    public:
        virtual bool init(int remote_port, char *remote_ip);
        virtual void close_conn(bool real_close = true);
        virtual void process(void);

    private:
        void init();
        
        bool connect_remote();
        
        bool send_request(void);
        bool generate_request(void);
        
        READ_STATUS read_response(void);
        READ_STATUS read_response_line_and_headers(void);
        READ_STATUS read_response_content(void);

        //parse request functions
        HTTP_CODE parse_response(void);
        HTTP_CODE parse_response_line(char* text);
        HTTP_CODE parse_response_line(void);
        HTTP_CODE parse_headers(char* text);
        HTTP_CODE parse_headers(void);
        HTTP_CODE parse_response_content(void);
        HTTP_CODE parse_response_content(char* text);
        
        LINE_STATUS parse_line(void);
        
        char* get_line(void)
        {
            return m_read_buf + m_start_line;
        }
        
        HTTP_CODE read_handle_func(void);
        HTTP_CODE write_handle_func(void);

        void unmap();
        bool add_request(const char* format, ...);
        bool add_content(const char* content);
        bool add_request_line(void);
        bool add_headers(int content_length);
        bool add_content_type(void);
        bool add_content_length(int content_length);
        bool add_linger(void);
        bool add_blank_line(void);

    public:
        static int m_epollfd;

        //enum HANDLE_TYPE handle_type;

        read_handle_t read_handle;
        write_handle_t write_handle;

        //bool is_read_ready;
        
        char remote_ip[20];
        
        int remote_port;

    private:
        //int m_sockfd;
        sockaddr_in m_address;

        int send_file_id;
        long send_file_count;
        unsigned long long send_file_size;
        
        char m_read_buf[READ_BUFFER_SIZE];
        int m_read_idx;
        int m_checked_idx;
        int m_start_line;
        
        int send_count;
        char m_write_buf[WRITE_BUFFER_SIZE];
        int m_write_idx;
        
        int send_end_count;
        int end_size;

        CHECK_STATE m_check_state;
        METHOD m_method;

        char m_real_file[FILENAME_LEN];
        
        //char m_upload_file_name[FILENAME_LEN];
        
        char* m_url;
        char* m_version;
        char* m_response_str;
        char* m_status_code;
        char* m_host;
        char* m_content_type;
        unsigned long long m_content_length;
        bool m_linger;

        char *m_file_address;
        struct stat m_file_stat;
        
        bool is_in_epoll;
};

#endif
